package com.wei.czz.common.utils;

import com.github.dozermapper.core.DozerBeanMapperBuilder;
import com.github.dozermapper.core.Mapper;
import com.wei.czz.common.exception.CzzException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.stream.Collector;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wyw
 * date: 2024-04-26 14:32:40
 * className: CopyUtils 映射工具类
 * version: 1.0
 * description:
 */
public class CopyUtils {

    private static final Logger log = LoggerFactory.getLogger(CopyUtils.class);

    /**
     * dozer映射操作对象
     */
    private static final Mapper mapper = DozerBeanMapperBuilder.buildDefault();

    /**
     * 对象映射
     * @param source 复制对象
     * @param target 目标Class对象
     * @return 目标对象
     * @param <T> 泛型
     * @param <U> 泛型
     */
    public static <T, U> U map(T source, Class<U> target) {
        return mapper.map(source, target);
    }

    /**
     * 对象映射
     * @param source 复制对象
     * @param target 目标对象
     * @return 目标对象
     * @param <T> 泛型
     * @param <U> 泛型
     */
    public static <T, U> U map(T source, U target) {
        mapper.map(source, target);
        return target;
    }

    /**
     * 列表映射
     * @param list   目标列表
     * @param target 目标Class对象
     * @return 目标对象列表
     * @param <T> 泛型
     * @param <U> 泛型
     */
    public static <T, U> List<U> mapList(List<T> list, Class<U> target) {
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>();
        }
        List<U> result = new ArrayList<>(list.size());
        for (T t : list) {
            U u = mapper.map(t, target);
            result.add(u);
        }
        return result;
    }

    /**
     * 列表映射
     * @param list     目标列表
     * @param target   目标Class对象
     * @param function 自定义调整映射结果表达式
     * @return 目标对象列表
     * @param <T> 泛型
     * @param <U> 泛型
     */
    public static <T, U> List<U> mapList(List<T> list, Class<U> target, BiFunction<T, U, U> function) {
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>();
        }
        List<U> result = new ArrayList<>(list.size());
        for (T t : list) {
            U u = mapper.map(t, target);
            u = function.apply(t, u);
            result.add(u);
        }
        return result;
    }

    /**
     * 列表映射
     * @param list       目标列表
     * @param target     目标Class对象
     * @param biConsumer 自定义调整映射结果表达式
     * @return 目标对象列表
     * @param <T> 泛型
     * @param <U> 泛型
     */
    public static <T, U> List<U> mapList(List<T> list, Class<U> target, BiConsumer<T, U> biConsumer) {
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>();
        }
        List<U> result = new ArrayList<>(list.size());
        for (T t : list) {
            U u = mapper.map(t, target);
            biConsumer.accept(t, u);
            result.add(u);
        }
        return result;
    }

    /**
     * 列表映射
     * @param list     目标列表
     * @param function 自定义映射表达式
     * @return 目标对象列表
     * @param <T> 泛型
     * @param <U> 泛型
     */
    public static <T, U> List<U> mapList(List<T> list, Function<T, U> function) {
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>();
        }
        List<U> result = new ArrayList<>(list.size());
        for (T t : list) {
            U u = function.apply(t);
            result.add(u);
        }
        return result;
    }

    /**
     * 列表映射
     * @param list     目标列表
     * @param function 自定义映射表达式
     * @return 目标对象集合
     * @param <T> 泛型
     * @param <U> 泛型
     */
    public static <T, U> Set<U> mapSet(List<T> list, Function<T, U> function) {
        if (CollectionUtils.isEmpty(list)) {
            return new HashSet<>();
        }
        Set<U> result = new HashSet<>(list.size());
        for (T t : list) {
            U u = function.apply(t);
            result.add(u);
        }
        return result;
    }

    /**
     * 列表转映射
     * @param list          目标列表
     * @param keyFunction   键生成表达式
     * @param valueFunction 值生成表达式
     * @return 目标映射对象
     * @param <T> 泛型
     * @param <K> 泛型
     * @param <V> 泛型
     */
    public static <T, K, V> Map<K, V> listToMap(List<T> list, Function<T, K> keyFunction,
                                                Function<T, V> valueFunction) {
        if (CollectionUtils.isEmpty(list)) {
            return new HashMap<>();
        }
        Map<K, V> map = new HashMap<>();
        for (T t : list) {
            // 生成key
            K key = keyFunction.apply(t);
            // 生成value
            V value = valueFunction.apply(t);
            if (Objects.isNull(value)) {
                /**
                 * 此处判断参考了{@link Collector}类的 uniqKeysMapAccumulator 方法
                 */
                log.error("映射值生成结果为空。t={}", t);
                throw new CzzException();
            }
            // 存储值
            V preValue = map.putIfAbsent(key, value);
            if (Objects.nonNull(preValue)) {
                /**
                 * 此处判断参考了{@link Collector}类的 uniqKeysMapAccumulator 方法
                 */
                log.error("映射值重复，映射失败。t={} key={} preValue={} value={}", t, key, preValue, value);
                throw new CzzException();
            }
        }
        return map;
    }

    /**
     * 列表转映射
     * @param list          目标列表
     * @param keyFunction   键生成表达式
     * @param valueFunction 值生成表达式
     * @return 目标映射对象
     * @param <T> 泛型
     * @param <K> 泛型
     * @param <V> 泛型
     */
    public static <T, K, V> Map<K, V> listToMap(List<T> list, Function<T, K> keyFunction, Function<T, V> valueFunction,
                                                BinaryOperator<V> mergeFunction) {
        if (CollectionUtils.isEmpty(list)) {
            return new HashMap<>();
        }
        Map<K, V> map = new HashMap<>();
        for (T t : list) {
            // 生成key
            K key = keyFunction.apply(t);
            // 生成value
            V value = valueFunction.apply(t);
            if (Objects.isNull(value)) {
                /**
                 * 此处判断参考了{@link Collector}类的 uniqKeysMapAccumulator 方法
                 */
                log.error("映射值生成结果为空。t={}", t);
                throw new CzzException();
            }
            // 获取key对应的前一个value
            V preValue = map.get(key);
            if (Objects.nonNull(preValue)) {
                /**
                 * 此处逻辑参考了{@link Collector}类的 toMap 方法
                 * 前后两个value计算得到最新value
                 */
                value = mergeFunction.apply(preValue, value);
            }
            map.put(key, value);
        }
        return map;
    }

}
